package com.sapitest.keywords.asserts;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;

import java.util.regex.PatternSyntaxException;

import static org.testng.Assert.fail;

/**
 * JSON数据的断言方法，包括JSONObject，JSONArray两种数据类型
 * @date 2019-01-13
 * @author Liuxu
 * @version 1.0.0
 * @since jdk1.8
 */
public class JSONAssert {
    private static final String JSON_FAILED_TEMPLATE = "Expected [%s], but found [%s]";

    /**
     * 比较jsonObject相等，key值的顺序不一样不影响比较结果
     * @param actual    实际结果
     * @param expected  期望结果
     */
    public static void jsonObjectEquals(String actual, String expected){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONObject acjo = JSON.parseObject(actual);
                JSONObject epjo = JSON.parseObject(expected);
                if (!acjo.equals(epjo)){
                    fail(String.format(JSON_FAILED_TEMPLATE, expected, actual));
                }
            } catch (JSONException e) {
                fail("Actual or expected is not jsonobject.");
            }
        }
    }

    /**
     * 比较jsonObject不相等，key值的顺序不一样不影响比较结果
     * @param actual    实际结果
     * @param expected  期望结果
     */
    public static void jsonObjectNotEquals(String actual, String expected){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONObject acjo = JSON.parseObject(actual);
                JSONObject epjo = JSON.parseObject(expected);
                if (acjo.equals(epjo)){
                    fail(String.format(JSON_FAILED_TEMPLATE, expected, actual));
                }
            } catch (JSONException e) {
                fail("Actual or expected is not jsonobject.");
            }
        }
    }

    /**
     * jsonObject包含key值
     * @param actual    实际结果
     * @param expectedKey   期望包含的key值
     */
    public static void jsonObjectHasKey(String actual, String expectedKey){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONObject jsonObject = JSON.parseObject(actual);
                if (!jsonObject.containsKey(expectedKey)) {
                    fail(String.format(JSON_FAILED_TEMPLATE, expectedKey, ""));
                }
            }catch (JSONException e){
                fail(String.format("[%s] is not jsonobject.", actual));
            }
        }
    }

    /**
     * jsonObject不包含key值
     * @param actual    实际结果
     * @param expectedKey   期望不包含的key值
     */
    public static void jsonObjectNotHasKey(String actual, String expectedKey){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONObject jsonObject = JSON.parseObject(actual);
                if (jsonObject.containsKey(expectedKey)) {
                    fail(String.format(JSON_FAILED_TEMPLATE, "", expectedKey));
                }
            }catch (JSONException e){
                fail(String.format("[%s] is not jsonobject.", actual));
            }
        }
    }

    /**
     * jsonObject包含value值
     * @param actual    实际结果
     * @param expectedValue 期望包含的value值
     */
    public static void jsonObjectHasValue(String actual, String expectedValue){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONObject jsonObject = JSON.parseObject(actual);
                if (!jsonObject.containsValue(expectedValue)) {
                    fail(String.format(JSON_FAILED_TEMPLATE, expectedValue, ""));
                }
            }catch (JSONException e){
                fail(String.format("[%s] is not jsonobject.", actual));
            }
        }
    }

    /**
     * jsonObject不包含value值
     * @param actual    实际结果
     * @param expectedValue 期望不包含的value值
     */
    public static void jsonObjectNotHasValue(String actual, String expectedValue){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONObject jsonObject = JSON.parseObject(actual);
                if (jsonObject.containsValue(expectedValue)) {
                    fail(String.format(JSON_FAILED_TEMPLATE, "", expectedValue));
                }
            }catch (JSONException e){
                fail(String.format("[%s] is not jsonobject.", actual));
            }
        }
    }

    /**
     * 比较jsonObject大小
     * @param actual    实际结果
     * @param expected  期望的大小
     */
    public static void jsonObjectSize(String actual, int expected){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONObject jsonObject = JSON.parseObject(actual);
                if (expected != jsonObject.size()) {
                    fail(String.format(JSON_FAILED_TEMPLATE, expected, jsonObject.size()));
                }
            }catch (JSONException e){
                fail(String.format("[%s] is not jsonobject.", actual));
            }
        }
    }

    /**
     * 比较jsonObject，严格匹配，包括key的顺序
     * @param actual    实际结果
     * @param expected  期望结果
     */
    public static void jsonObjectStrictEquals(String actual, String expected){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONObject acjo = JSON.parseObject(actual);
                JSONObject epjo = JSON.parseObject(expected);
                if (!acjo.toJSONString().equals(epjo.toJSONString())){
                    fail(String.format(JSON_FAILED_TEMPLATE, expected, actual));
                }
            } catch (JSONException e) {
                fail("Actual or expected is not jsonobject.");
            }
        }
    }

    /**
     * 比较jsonArray是否相等
     * @param actual    实际结果
     * @param expected  期望结果
     */
    public static void jsonArrayEquals(String actual, String expected){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONArray acja = JSON.parseArray(actual);
                JSONArray epja = JSON.parseArray(expected);
                if (!acja.equals(epja)){
                    fail(String.format(JSON_FAILED_TEMPLATE, expected, actual));
                }
            } catch (JSONException e){
                fail("Actual or expected is not jsonobject.");
            }
        }
    }

    /**
     * 比较jsonArray的大小
     * @param actual    实际结果
     * @param expected  期望的大小
     */
    public static void jsonArraySize(String actual, int expected){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                JSONArray acja = JSON.parseArray(actual);
                if (expected != acja.size()){
                    fail(String.format(JSON_FAILED_TEMPLATE, expected, acja.size()));
                }
            } catch (JSONException e){
                fail(String.format("[%s] is not jsonArray.", actual));
            }
        }
    }

    /**
     * 忽略部分keys，比较jsonObject
     * @param actual    实际结果
     * @param expected  期望结果
     * @param keys  需要去除的keys，格式为"key1,key2,key3..."，不同key直接用","隔开
     */
    public static void jsonObjectEqualsIgnoreKeys(String actual, String expected, String keys){
        if ("".equals(actual) || null == actual) {
            fail("Actual result is \"\" or null.");
        } else {
            try {
                String[] lists = keys.split(",");
                JSONObject acjo = JSON.parseObject(actual);
                JSONObject epjo = JSON.parseObject(expected);
                for (String list:lists) {
                    acjo = acjo.fluentRemove(list);
                }
                if (!acjo.equals(epjo)){
                    fail(String.format(JSON_FAILED_TEMPLATE, expected, acjo));
                }
            } catch (JSONException |PatternSyntaxException e){
                fail("Parameter error.");
            }
        }
    }

}
